/*
 * lib2Desa - Another 2D game library in C++
 * Copyright (C) 2009 Erivaldo Xavier de Lima Filho
 *
 * This program is free software and is distributed under GNU General Public License version 3. You can modify and/or redistribute
 * it under the terms of GPL version 3 or posterior version. This program comes with NO WARRANTY, for more details, see LICENSE,
 * or <http://www.gnu.org/licenses>.
 *
 * Contact info:
 *
 *	Erivaldo Xavier de Lima Filho, desadoc@gmail.com
 *
 */

#ifndef _VECTOR_HPP
#define _VECTOR_HPP

#include "Core/types.hpp"
//#include "Core/RefCounter.hpp"

#ifndef _NO_NAMESPACE
namespace lib2Desa {
#endif

template <u32 D, typename T>
class vector
{

private:

	T v[D];

public:

	vector(void)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] = T();
	}

	vector(const T vals[])
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] = vals[i];
	}

	vector(const T x, const T y, const T z=T(0), const T w=T(1))
	{
		switch(D)
		{
			case 4: v[3] = w;
			case 3: v[2] = z;
			case 2: v[1] = y;
			case 1: v[0] = x; break;
			default: break;
		}
	}

	T& operator[](unsigned int p)
	{
		return v[p];
	}

	const T operator[](unsigned int p) const
	{
		return v[p];
	}

#define get_x() operator[](0)
#define get_y() operator[](1)
#define get_z() operator[](2)
#define get_w() operator[](3)

	const vector& operator=(const vector& vec)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] = vec.v[i];

		return *this;
	}

	const vector& operator=(const T vals[])
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] = vals[i];

		return *this;
	}

	const vector operator+(const vector& vec) const
	{
		u32 i;
		vector<D,T> _v;

		for(i=0; i<D; i++)
			_v.v[i] = v[i] + vec.v[i];

		return _v;
	}

	const vector& operator+=(const vector& vec)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] += vec.v[i];

		return *this;
	}

	const vector operator-(const vector& vec) const
	{
		u32 i;
		vector<D,T> _v;

		for(i=0; i<D; i++)
			_v.v[i] = v[i] - vec.v[i];

		return _v;
	}

	const vector& operator-=(const vector& vec)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] -= vec.v[i];

		return *this;
	}

	const vector operator*(const T fac) const
	{
		u32 i;
		vector<D,T> _v;

		for(i=0; i<D; i++)
			_v.v[i] = v[i] * fac;

		return _v;
	}

	const T operator*(const vector& vec) const
	{
		int i;
		T acum = 0;

		for(i=0; i<D; i++)
			acum += v[i]*vec.v[i];

		return acum;
	}

	const vector& operator*=(const T fac)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] *= fac;

		return *this;
	}

	const vector operator/(const T fac) const
	{
		u32 i;
		vector<D,T> _v;

		for(i=0; i<D; i++)
			_v.v[i] = v[i] / fac;

		return _v;
	}

	const vector& operator/=(const T fac)
	{
		u32 i;

		for(i=0; i<D; i++)
			v[i] /= fac;

		return *this;
	}

	template <u32 ND, typename NT>
	operator vector<ND, NT>(void) const
	{
		u32 i;
		vector<ND,T> _v;

		if(D>=ND)
		{
			for(i=0; i<ND; i++)
				_v[i] = v[i];
		} else {
			for(i=0; i<D; i++)
				_v[i] = v[i];

			for(i=D; i<ND; i++)
				_v[i] = 0;
		}

		return _v;
	}
};

typedef vector<2,f32> vector2f;
typedef vector<3,f32> vector3f;
typedef vector<4,f32> vector4f;

typedef vector<2,f64> vector2lf;
typedef vector<3,f64> vector3lf;
typedef vector<4,f64> vector4lf;

typedef vector<2,s32> vector2i;
typedef vector<3,s32> vector3i;
typedef vector<4,s32> vector4i;

typedef vector<2,s64> vector2li;
typedef vector<3,s64> vector3li;
typedef vector<4,s64> vector4li;

typedef vector<2,u32> vector2u;
typedef vector<3,u32> vector3u;
typedef vector<4,u32> vector4u;

typedef vector<2,u64> vector2lu;
typedef vector<3,u64> vector3lu;
typedef vector<4,u64> vector4lu;

#ifndef _NO_NAMESPACE
}
#endif

#endif /*vector.hpp included*/
